home *** CD-ROM | disk | FTP | other *** search
- // Quickdraw 3D sample code
- //
- // This file illustrates how to set up a pixmap based draw context.
- // A metafile is read into and imaged in the pixmap, this pixmap is combined
- // with a pixmap containing a background, so that the 3d data is drawn over
- // the background
- //
- // Nick Thompson, AppleLink: DEVSUPPORT (devsupport@applelink.apple.com)
- //
- // ©1994-5 Apple Computer Inc., All Rights Reserved
-
-
- // system headers
- #include <Menus.h>
- #include <Devices.h>
- #include <Events.h>
- #include <Dialogs.h>
- #include <DiskInit.h>
- #include <Fonts.h>
- #include <Menus.h>
- #include <PictUtils.h>
- #include <QDOffScreen.h>
- #include <QuickDraw.h>
- #include <SegLoad.h>
- #include <StandardFile.h>
- #include <TextEdit.h>
- #include <ToolUtils.h>
- #include <Timer.h>
- #include <Processes.h>
- #include <string.h>
-
- // for QuickDraw 3D
- #include "QD3D.h"
- #include "QD3DMath.h"
- #include "QD3DDrawContext.h"
- #include "QD3DShader.h"
- #include "QD3DTransform.h"
- #include "QD3DGroup.h"
- #include "QD3DCamera.h"
-
-
- #include "BackGroundShell.h"
- #include "BackGroundSupport.h"
-
- // get the interface to my error handler routines
- #include "MyErrorHandler.h"
-
- #define ONE_SECOND 1000000
- #define MILLIONTHS 0.000001F
- #define MAX( a, b ) ( ((a) > (b)) ? (a) : (b) )
-
- /*
- * control use of ATI VRAM for GWorld pixmaps
- */
- #define USE_ATI_OFF_SCREEN_MEM_MANAGER 1
- #if USE_ATI_OFF_SCREEN_MEM_MANAGER
- #include "atimem.h"
-
- QDErr NewGWorldVRAM( GWorldPtr *offscreenGWorld, short PixelDepth, const Rect *boundsRect,
- CTabHandle cTable, GDHandle aGDevice, GWorldFlags flags, GDHandle gdh );
- void DisposeGWorldVRAM( GWorldPtr offscreenGWorld );
- void VRAMCallBack( GDHandle hGDevice, unsigned int flag, void *data );
- int ATI_IsVRAMGWorld( GWorldPtr offscreenGWorld );
- int gCallbackIndex;
- int gNumGWorldVRAM = 0;
- #endif
-
- const RGBColor kClearColor = { 0x0000, 0xffff, 0x0000 } ;
- const RGBColor kWhiteColor = { 0xffff, 0xffff, 0xffff } ;
-
- //-------------------------------------------------------------------------------------------
- // function prototypes
-
- static void InitToolbox( void ) ;
- static void MainEventLoop( void ) ;
- static void HandleKeyPress(EventRecord *event) ;
- static void HandleOSEvent(EventRecord *event) ;
- void InitDocumentData( DocumentPtr theDocument ) ;
- TQ3Status DocumentDraw3DData( DocumentPtr theDocument ) ;
- void DisposeDocumentData( DocumentPtr theDocument) ;
- void DocumentDrawOnscreen(DocumentPtr theDocument, Rect *clipRect) ;
-
- OSErr WritePict( PicHandle myPic, short dstPictFRef ) ;
- OSErr GetOutputFileRef(short *dstPictFRef ) ;
- PicHandle ImageToPict( DocumentPtr theDocument, WindowPtr theWindow ) ;
- void DoSaveAs(DocumentPtr theDocument) ;
- unsigned long MicrosecondCount( void );
- void DisplayString( int x, int y, char *str );
-
- //-------------------------------------------------------------------------------------------
- //
-
- Boolean gQuitFlag = false ;
- WindowPtr gMainWindow = nil ;
- DocumentRec gDocument ;
-
- unsigned long start, end;
- float seconds;
- unsigned long count = 0;
- char str[100];
- RGBColor BLACK = { 0, 0, 0 };
-
- //-------------------------------------------------------------------------------------------
- // main()
- // entry point for the application, initialize the toolbox, initialize QuickDraw 3D
- // and enter the main event loop. On exit from the main event loop, we want to call
- // the QuickDraw 3D exit function to clean up QuickDraw 3d.
-
- void main(void)
- {
- TQ3Status myStatus;
- int stat = true;
- Rect rBounds = { 50, 50, 200, 200 };
- Str255 title = "\pSpinning Box" ;
- FSSpec theFileSpec ; // the file we are opening
- GDHandle gdh;
-
- InitToolbox() ;
-
-
- if(MetafileFileSpecify( &theFileSpec )) {
-
- SetCursor(*(GetCursor(watchCursor)));
-
- // Initialize QuickDraw 3D, open a connection to the QuickDraw 3D library
- myStatus = Q3Initialize();
- if ( myStatus == kQ3Failure )
- DebugStr("\pErInitialize returned failure.");
-
- // install the error & warning handler - these get called whenever
- // errors or warnings occur, which means we don't have to check so
- // much
- Q3Error_Register( MyErrorHandler, 0L );
- Q3Warning_Register( MyWarningHandler, 0L );
-
- // set up our globals
- gQuitFlag = false ;
- gMainWindow = NewCWindow(nil,&rBounds,title,false,noGrowDocProc,(WindowPtr)-1,true,nil); ;
-
- // initialise our document structure
- InitDocumentData( &gDocument ) ;
-
- // try to read the file into the main display group
- if((gDocument.fModel = MyNewModelFromFile(&theFileSpec)) != NULL ) {
-
- // get a bg picture
- if(PictureFileSpecify(&theFileSpec)) {
- PicHandle thePicture ;
- if((thePicture = OpenPICTFile( &theFileSpec )) != nil ) {
-
- CGrafPtr savedPort ;
- OSErr theErr ;
- Rect bounds = (**thePicture).picFrame ;
-
- GetGWorld( &savedPort, &gdh );
-
- #if USE_ATI_OFF_SCREEN_MEM_MANAGER
- /*
- * try to allocate GWorld for background image
- * on VRAM - if "background_image"is NULL then
- * VRAM allocation failed and GWorld is ordinary
- * one in system memory
- */
- theErr = NewGWorldVRAM( &gDocument.fBgPicture,
- (**((**gdh).gdPMap)).pixelSize,
- &bounds,
- nil,
- nil,
- 0L,
- gdh );
- #else
- // create the offscreen for the picture, this is faster than
- // calling DrawPicture each time through our update onscreen routine.
- theErr = NewGWorld( &gDocument.fBgPicture,
- (**((**gdh).gdPMap)).pixelSize,
- &bounds,
- nil,
- nil,
- 0L );
- #endif
-
- if( theErr != noErr || stat == false )
- ExitToShell() ;
-
- SetGWorld( gDocument.fBgPicture, nil ) ;
- DrawPicture( thePicture, &bounds ) ;
- KillPicture( thePicture ) ;
-
- #if USE_ATI_OFF_SCREEN_MEM_MANAGER
- /*
- * try to allocate GWorld for composite image
- * on VRAM - if "composite_image"is NULL then
- * VRAM allocation failed and GWorld is ordinary
- * one in system memory
- */
- theErr = NewGWorldVRAM( &gDocument.fCompositeBuffer,
- (**((**gdh).gdPMap)).pixelSize,
- &bounds,
- nil,
- nil,
- 0L,
- gdh );
- #else
- theErr = NewGWorld( &gDocument.fCompositeBuffer,
- (**((**gdh).gdPMap)).pixelSize,
- &bounds,
- nil,
- nil,
- 0L );
- #endif
- if( theErr != noErr )
- ExitToShell() ;
-
- // clear our compositing buffer
- SetGWorld( gDocument.fCompositeBuffer, nil ) ;
- RGBBackColor( &kClearColor ) ;
- EraseRect( &bounds ) ;
-
- // restore the environment
- SetGWorld( savedPort, gdh );
-
- AdjustCamera( &gDocument,
- (bounds.right - bounds.left),
- (bounds.bottom - bounds.top) ) ;
-
- SetWTitle( gMainWindow, theFileSpec.name );
-
- SizeWindow( gMainWindow,
- (bounds.right - bounds.left),
- (bounds.bottom - bounds.top),
- false );
-
- ShowWindow( gMainWindow ) ;
- SetPort( gMainWindow ) ;
-
- SetCursor(&qd.arrow) ;
- MainEventLoop();
- }
- }
-
- }
-
- DisposeDocumentData( &gDocument );
-
- // Close our connection to the QuickDraw 3D library
- myStatus = Q3Exit();
- if ( myStatus == kQ3Failure )
- DebugStr("\pErExit returned failure.");
- }
- }
-
- //-------------------------------------------------------------------------------------------
- //
-
- void InitDocumentData( DocumentPtr theDocument )
- {
- GWorldPtr theOffscreen ;
- GDHandle theDevice ;
- TQ3Point3D myOrigin = { 0, 0, 0 } ;
- OSErr myErr;
-
- GetGWorld( &theOffscreen, &theDevice ) ;
-
- #if USE_ATI_OFF_SCREEN_MEM_MANAGER
- /*
- * try to allocate GWorld for drawing image
- * on VRAM - if "draw_image"is NULL then
- * VRAM allocation failed and GWorld is
- * ordinary one in system memory
- */
- myErr = NewGWorldVRAM( &gDocument.fGWorld,
- (**((**theDevice).gdPMap)).pixelSize,
- &gMainWindow->portRect,
- nil,
- nil,
- 0L,
- theDevice );
- #else
- // create the offscreen for the picture, this is faster than
- // calling DrawPicture each time through our update onscreen routine.
- myErr = NewGWorld( &gDocument.fGWorld,
- (**((**theDevice).gdPMap)).pixelSize,
- &gMainWindow->portRect,
- nil,
- nil,
- 0L );
- #endif
-
- if(myErr != noErr )
- goto bail ;
-
- SetGWorld( theDocument->fGWorld, nil ) ;
- EraseRect( &gMainWindow->portRect ) ;
- SetGWorld( theOffscreen, theDevice ) ;
-
- // sets up the 3d data for the scene
- // Create view for QuickDraw 3D.
- theDocument->fView = MyNewView( theDocument->fGWorld );
-
- // the main display group:
- theDocument->fModel = NULL ;
-
- // scale and group center
- theDocument->fGroupScale = 1;
- theDocument->fGroupCenter = myOrigin ;
-
- // the drawing styles:
- theDocument->fInterpolation = Q3InterpolationStyle_New(kQ3InterpolationStyleNone) ;
- theDocument->fBackFacing = Q3BackfacingStyle_New( kQ3BackfacingStyleBoth ) ;
- theDocument->fFillStyle = Q3FillStyle_New(kQ3FillStyleFilled ) ;
-
- // set the rotation matrix the identity matrix
- Q3Matrix4x4_SetIdentity(&theDocument->fRotation);
-
- return ;
-
- bail:
- // we failed setting up the GWorld
- // so we want to quit here
- ExitToShell() ;
-
- }
-
- void DisposeDocumentData( DocumentPtr theDocument)
- {
-
- #if USE_ATI_OFF_SCREEN_MEM_MANAGER
- if( theDocument->fGWorld )
- DisposeGWorldVRAM( theDocument->fGWorld );
-
- if( theDocument->fBgPicture )
- DisposeGWorldVRAM( theDocument->fBgPicture );
-
- if( theDocument->fCompositeBuffer )
- DisposeGWorldVRAM( theDocument->fCompositeBuffer );
- #else
- if( theDocument->fGWorld )
- DisposeGWorld( theDocument->fGWorld );
-
- if( theDocument->fBgPicture )
- DisposeGWorld( theDocument->fBgPicture );
-
- if( theDocument->fCompositeBuffer )
- DisposeGWorld( theDocument->fCompositeBuffer );
- #endif
-
- if(theDocument->fView)
- Q3Object_Dispose(theDocument->fView) ; // the view for the scene
-
- if(theDocument->fModel)
- Q3Object_Dispose(theDocument->fModel) ; // object in the scene being modelled
-
- if(theDocument->fInterpolation)
- Q3Object_Dispose(theDocument->fInterpolation) ; // interpolation style used when rendering
-
- if(theDocument->fBackFacing)
- Q3Object_Dispose(theDocument->fBackFacing) ; // whether to draw shapes that face away from the camera
-
- if(theDocument->fFillStyle)
- Q3Object_Dispose(theDocument->fFillStyle) ; // whether drawn as solid filled object or decomposed to components
- }
- //-----------------------------------------------------------------------------
- // assumes the port is set up before being called
-
- TQ3Status DocumentDraw3DData( DocumentPtr theDocument )
- {
- TQ3Status theStatus ;
-
- // Start rendering.
- Q3View_StartRendering(theDocument->fView) ;
- do {
- theStatus = SubmitScene( theDocument ) ;
- } while (Q3View_EndRendering(theDocument->fView) == kQ3ViewStatusRetraverse );
-
- return theStatus ;
- }
-
- //-------------------------------------------------------------------------------------------
- //
-
- void DocumentDrawOnscreen(DocumentPtr theDocument, Rect *clipRect)
- {
- if (theDocument->fGWorld) {
-
- CGrafPtr savedPort;
- GDHandle savedDevice;
- RGBColor savedColor ;
-
- GetGWorld( &savedPort, &savedDevice);
- // composite the image in the offscreen
- // first draw the BG Pict
- SetGWorld( theDocument->fCompositeBuffer, nil);
-
- GetBackColor(&savedColor);
- RGBBackColor(&kWhiteColor) ;
-
- CopyBits ((BitMapPtr) &theDocument->fBgPicture->portPixMap,
- (BitMapPtr) &theDocument->fCompositeBuffer->portPixMap,
- &theDocument->fBgPicture->portRect,
- &theDocument->fCompositeBuffer->portRect,
- srcCopy,
- 0L);
-
- RGBBackColor(&savedColor) ;
- OpColor(&kClearColor);
-
- // next draw the 3d image over the bg pict using transparent copy
- CopyBits ((BitMapPtr) &theDocument->fGWorld->portPixMap,
- (BitMapPtr) &theDocument->fCompositeBuffer->portPixMap,
- &theDocument->fGWorld->portRect,
- &theDocument->fCompositeBuffer->portRect,
- srcCopy | transparent,
- 0L);
- SetGWorld( (CGrafPtr)gMainWindow, nil);
-
- ClipRect( clipRect ) ;
-
-
- // don't need to lockPixels on the GWorld as the
- // offscreen remains locked (see IM: QD3D), the
- // pixmap for a pixmap draw context must remain locked
-
- CopyBits ((BitMapPtr) &theDocument->fCompositeBuffer->portPixMap,
- &gMainWindow->portBits,
- &theDocument->fCompositeBuffer->portRect,
- &gMainWindow->portRect,
- srcCopy,
- 0L);
-
- SetGWorld( savedPort, savedDevice);
- }
- }
-
-
- //-------------------------------------------------------------------------------------------
- //
-
- short HiWrd(long aLong)
- {
- return (((aLong) >> 16) & 0xFFFF) ;
- }
-
- //-------------------------------------------------------------------------------------------
- //
-
- short LoWrd(long aLong)
- {
- return ((aLong) & 0xFFFF) ;
-
- }
-
- //-------------------------------------------------------------------------------------------
- //
-
- void InitToolbox()
- {
- Handle menuBar = nil;
-
- MaxApplZone() ;
- MoreMasters() ; MoreMasters() ; MoreMasters() ;
-
- InitGraf( &qd.thePort );
- InitFonts();
- InitWindows();
-
- FlushEvents( everyEvent, 0 ) ;
- // initialize application globals
-
- gQuitFlag = false;
- InitCursor();
-
- }
-
- //-------------------------------------------------------------------------------------------
- //
- void MainEventLoop()
- {
- EventRecord event;
- WindowPtr window;
- short thePart;
- Rect screenRect, updateRect;
- Point aPoint = {100, 100};
-
- start = MicrosecondCount();
-
- while( !gQuitFlag )
- {
- if (WaitNextEvent( everyEvent, &event, 0, nil ))
- {
-
- switch (event.what) {
- case mouseDown:
-
- thePart = FindWindow( event.where, &window );
-
- switch( thePart ) {
- case inMenuBar:
- break;
-
- case inDrag:
-
- screenRect = (**GetGrayRgn()).rgnBBox;
- DragWindow( window, event.where, &screenRect );
- break ;
-
- case inContent:
-
- if (window != FrontWindow())
- SelectWindow( window );
- break ;
-
- case inGoAway:
- if (TrackGoAway( window, event.where )) {
- DisposeWindow ( window );
- gQuitFlag = true;
-
- }
- break ;
-
- default:
- break ;
- }
- break ;
-
-
- case updateEvt:
-
- window = (WindowPtr)event.message;
- updateRect = (**(window->visRgn)).rgnBBox;
- SetPort( window ) ;
-
- BeginUpdate( window );
- DocumentDraw3DData( &gDocument ) ;
- DocumentDrawOnscreen( &gDocument, &updateRect ) ;
- EndUpdate( window );
-
- /*
- * display frame rate
- */
- end = MicrosecondCount();
- seconds = (float)(MAX((end-start),1))*MILLIONTHS;
- sprintf( str, "fps = %5.2f", ++count/seconds);
- DisplayString( 2, 10, str );
- break ;
-
- case keyDown:
- case autoKey:
- HandleKeyPress(&event);
- break;
-
- case diskEvt:
- if ( HiWrd(event.message) != noErr )
- (void) DIBadMount(aPoint, event.message);
- break;
-
- case osEvt:
- case activateEvt:
- break;
- }
- }
- else {
- // we received a null event, rotate the cube
- TQ3Matrix4x4 tmp;
- Rect theRect = ((GrafPtr)gMainWindow)->portRect ;
-
- SetPort((GrafPtr)gMainWindow) ;
- Q3Matrix4x4_SetRotate_XYZ(&tmp, 0.1, 0.12, 0.08);
- Q3Matrix4x4_Multiply(&gDocument.fRotation, &tmp, &gDocument.fRotation);
-
- InvalRect( &theRect ) ;
- }
- }
- }
-
-
- //-------------------------------------------------------------------------------------------
- //
- void HandleKeyPress(EventRecord *event)
- {}
-
- //-------------------------------------------------------------------------------------------
- //
-
- /*
- * Function: MicrosecondCount()
- *
- */
- unsigned long MicrosecondCount( void )
- {
- UnsignedWide currentCount;
-
- Microseconds(¤tCount);
-
- return( currentCount.lo );
- }
-
- /*
- * Function: DisplayString()
- *
- */
- void DisplayString( int x, int y, char *str )
- {
- char buf[256];
-
- RGBForeColor( &BLACK );
- MoveTo( x, y );
-
- strcpy( buf+1, str );
- buf[0] = strlen( buf+1 );
- DrawString( (const unsigned char *)buf );
- }
-
- #if USE_ATI_OFF_SCREEN_MEM_MANAGER
-
- QDErr NewGWorldVRAM( GWorldPtr *offscreenGWorld, short PixelDepth, const Rect *boundsRect,
- CTabHandle cTable, GDHandle aGDevice, GWorldFlags flags, GDHandle gdh )
- {
- OSErr myErr;
- unsigned long rowBytes;
- Ptr data;
-
- /*
- * create a GWorld the size of the boundsRect
- */
- myErr = NewGWorld( offscreenGWorld,
- PixelDepth,
- boundsRect,
- cTable,
- aGDevice,
- flags );
-
- if( myErr != noErr || HAS_ATI_OFFSCREEN_MEM() == false )
- return( myErr );
-
- /*
- * allocate block of VRAM on HW accelerator card
- */
- data = (Ptr)ATIMem_AllocVRAM( gdh,
- boundsRect->right - boundsRect->left,
- boundsRect->bottom - boundsRect->top,
- PixelDepth,
- &rowBytes,
- NULL,
- false, 0, 0,
- NULL );
-
- if( data )
- {
- /*
- * get PixMapHandle for GWorld + handle to pixel data
- * for PixMap of GWorld. Note: Inside Macintosh - Imaging
- * with Quickdraw, p. 4-46 states, "The baseAddr field
- * of the PixMap record for an offscreen graphics world
- * contains a handle instead of a pointer."
- */
- PixMapPtr pixPtr = *GetGWorldPixMap( *offscreenGWorld );
- Handle hndl = NewEmptyHandle();
-
- /*
- * lock handle and delete pixel memory of PixMap
- */
- DisposeHandle( (Handle)pixPtr->baseAddr );
-
- *hndl = data;
- pixPtr->baseAddr = (Ptr)hndl;
-
- //HLock( pixPtr->baseAddr );
-
- /*
- * set baseAddr to be handle to VRAM allocated on card +
- * adjust rowBytes to requirements of VRAM
- */
- pixPtr->rowBytes &= 0xC000;
- pixPtr->rowBytes |= rowBytes & 0x3FFF;
-
- /*
- * register for callback in case of mode switch
- * where contents of VRAM are deleted
- */
- if( gNumGWorldVRAM++ == 0 )
- gCallbackIndex = ATIMem_RegHeapCallback( gdh, VRAMCallBack, NULL );
- }
-
- return( noErr );
- }
-
- void DisposeGWorldVRAM( GWorldPtr offscreenGWorld )
- {
- PixMapHandle pixHndl;
- PixMapPtr pixPtr;
- CGrafPtr savedPort;
- GDHandle gdh;
-
- if( !offscreenGWorld )
- return;
-
- if( !HAS_ATI_OFFSCREEN_MEM() )
- {
- DisposeGWorld( offscreenGWorld );
- return;
- }
-
- pixHndl = GetGWorldPixMap( offscreenGWorld );
-
- if( pixHndl )
- {
- pixPtr = *pixHndl;
-
- if( pixPtr && pixPtr->baseAddr && ATI_IsVRAMGWorld(offscreenGWorld) )
- {
- /*
- * free VRAM allocated on card + then set
- * baseAddr to NULL so DisposeGWorld doesn't
- * try to free VRAM
- */
- GetGWorld( &savedPort, &gdh );
-
- ATIMem_FreeVRAM( gdh, pixPtr->baseAddr );
- ATIMem_FreeVRAM( gdh, *((Handle)(pixPtr->baseAddr)) );
- *(pixPtr->baseAddr) = NULL;
-
- if( --gNumGWorldVRAM == 0 )
- ATIMem_DeregHeapCallback( gdh, gCallbackIndex );
- }
- }
-
- DisposeGWorld( offscreenGWorld );
- }
-
- int ATI_IsVRAMGWorld( GWorldPtr offscreenGWorld )
- {
- PixMapHandle pixHndl;
- PixMapPtr pixPtr;
- CGrafPtr savedPort;
- GDHandle gdh;
-
- if( !offscreenGWorld || !HAS_ATI_OFFSCREEN_MEM() )
- return( false );
-
- if( (pixHndl = GetGWorldPixMap(offscreenGWorld)) == NULL ||
- (pixPtr = *pixHndl) == NULL || pixPtr->baseAddr == NULL )
- return( false );
-
- GetGWorld( &savedPort, &gdh );
-
- if( ATIMem_IsOnVRAM(gdh, pixPtr->baseAddr) ||
- ATIMem_IsOnVRAM(gdh, *((Handle)(pixPtr->baseAddr))) )
- {
- return( true );
- }
-
- return( false );
- }
-
- void VRAMCallBack( GDHandle hGDevice, unsigned int flag, void *data )
- {
- /*
- * set baseAddr to NULL so DisposeGWorld doesn't
- * try to free VRAM when DisposeDocumentData() is
- * called
- */
- DisposeGWorldVRAM( gDocument.fGWorld );
- gDocument.fGWorld = NULL;
-
- DisposeGWorldVRAM( gDocument.fBgPicture );
- gDocument.fBgPicture = NULL;
-
- DisposeGWorldVRAM( gDocument.fCompositeBuffer );
- gDocument.fCompositeBuffer = NULL;
-
- gQuitFlag = true;
- }
-
- #endif
-